""" Core.py
    
    Defines functions and classes related to the engine's core.
"""

import pygame
import debug
import video
import draw as _draw

__all__ = (
    'init',
    'start',
    'update',
)

# Constants
DEFAULT_TICKS = 30
HOOKPOINT = {
    'update_first' : 0, # For users
    'update_inputs' : 1, # Used for updating user inputs
    'update_worlds' : 2, # Used for updating worlds
    'update_cameras' : 3, # For updating cameras
    'update_last' : 4, # For users
    'draw_cameras' : 5, # For drawing cameras to the screen
    'draw_last' : 6, # For users
    'update_system' : 7 # For various last-minute system things
}

# Default values
_clock = None # Reference to the clock used to control the game speed.
_ticks = DEFAULT_TICKS # Number of game ticks, or "cycles", per second
_quit = False # When set to True, the main loop will end.
_init = False # Whether or not the core has been initialized.
_hook = ([],)*len(HOOKPOINT) # All hookpoints

def init(ticks=None):
    """ Initializes the core.
        
        You don't need to call this if you call sbak.init(). If you DO call it,
        however, you should call sbak.video.init() first.
        
        Pass the number of ticks, or "cycles," per second.
        
        This function is safe to call multiple times. Multiple calls are
        ignored.
    """
    global _clock, _ticks, _init
    if not _init:
        if ticks is None:
            ticks = DEFAULT_TICKS
        debug.message("Initializing core at %i ticks per second."%ticks)
        _clock = pygame.time.Clock()
        _ticks = ticks
        add_hook('update_system', _reg_speed)
        _init = True

def start():
    """ Starts the engine.
        This will start the main game loop and will automatically call update
        and draw as needed.
        You can specify functions to be called before and after each update and
        another to be called just before changes to the screen are committed,
        i.e. just before video.update() is called.
    """
    while not _quit:
        for hp in _hook:
            for h in hp:
                h()

def finish():
    """ Sets the internal `quit` flag, causing the main loop to halt. """
    global _quit
    _quit = True

def get_fps():
    """ Returns the current number of frames per second. """
    return _clock.get_fps()

def _reg_speed():
    """ Internal function.
        This is used to regulate game speed.
    """
    _clock.tick(_ticks)

def add_hook(hookPoint, callback):
    """ Appends a callback to the list of hooks for the given hook point.
        
        For hookPoint, pass the name of a hook point, such as "update_first".
        For callback, pass any callable object.
        
        Returns a tuple which can be used to remove the hook later. The tuple
        contains 2 values: The first is a number which represents the hook
        point, and the second is the callback.
        
        NOTES:
        * A callable can be registered more than once in a hookpoint.
        * It is possible to register 
    """
    hpNum = HOOKPOINT[hookPoint]
    hNum = len(_hook[hpNum])
    _hook[hpNum].append(callback)
    return (hpNum,callback)

def remove_hook(hook):
    """ Removes a hook.
        Pass the tuple returned by add_hook() when the hook was created.
    """
    _hook[hook[0]].remove(hook[1])

def set_ticks(ticks):
    """ Changes the number of ticks per second. """
    global _ticks
    _ticks = ticks
    
def get_ticks(ticks):
    """ Returns the number of ticks per second. """
    return _ticks
